//全局变量区域
#include<stdio.h>

//程序1
//二级指针的认识
void test1()
{
	int num = 520;
	int* p1 = &num;
	int** p2 = &p1;
/*或许你这个有疑问，我们前面学过指针它本质上是一个地址是吧，那为什么还要取出p的指针的地址呢？你指向指针的指针不就是要一个地址吗？那 p 不就是一个地址吗？这里来个演示

	int num = 520;
	int* p = &num;
	printf("*p = %p\n", p);//这里的打印的是指针 p 的"值"（注意是值，不是本身），即 num 的地址。
	printf("*p = %p\n", &p);//这里才是打印指针 p 本身的地址。
	printf("num = %p", &num);//这里打印的就是 num 的地址，等效于注释中第三行代码。
	
	那这里你估计就有眉目了,
	int* p1 = &num;//这里定义了一个指针 p ，类型是int*,它指向的"值"就是 num 的地址。
	int** p2 = &p1;//这里定义了一个指向指针的指针 p2 ,它的类型就是int**,它指向的"值"就是指针 p 的地址。
	
	扩展一下知识点你就理解了,
	一级指针 (int*): 直接指向一个整数变量。
	二级指针 (int**)<也叫指向指针的指针>: 指向一个一级指针，即存储一级指针的地址。
	三级指针 (int***): 指向一个二级指针，即存储二级指针的地址。

*/
	int*** p3 = &p2;

	printf("num = p\n", &num);// 打印变量num的地址	
	printf("*p1 = %p\n", p1);// 打印指针p1的值（它所指向的地址）
	printf("&p1 = %p\n", &p1);// 打印指针p1本身的地址
	printf("**p2 = %p\n", p2);// 打印指针p2指向的地址（即p1的地址）
	printf("&p2 = %p\n", &p2);// 打印指针p2本身的地址
	printf("***p3 = %p\n", p3);// 打印指针p3指向的地址（即p2的地址）
	printf("&p3 = %p", &p3);// 打印指针p3本身的地址


}

//程序2
//作业解析，这个其实就是回顾指针数组和数组指针的应用
void test2()
{
	//初始化指针数组
	const char* pArray[4] = {
		"Hello!",
		"HOW ARE YOU",
		"Fine ,thank you .And you?",
		"I'm FINE too"
	};

	const char* (*p)[4] = &pArray;

	int i;
	for (i = 0; i < 4; i++)
	{
		printf("%s\n", (*p)[i]);
	}


}

//程序3
//指针法访问三维数组的元素
void test3()
{
	char a[4][3][2] = {
		//a[0]
		{
			{'a','b'},{'c','d'},{'e','f'}
		},
		//a[1]
		{
			{'g','h'},{'i','j'},{'k','l'}
		},
		//a[2]
		{
			{'m','n'},{'o','p'},{'q','r'}
		},
		//a[3]
		{
			{'s','t'},{'u','v'},{'w','x'}
		}
	};

	const char (*pa)[2] = &a[1][0];//指向一维数组{'g','h'}
	const char (*ppa)[3][2] = &a[1];//指向二维数组a[1]

	printf("*pa = %c\n", *(*(pa + 8) + 1));//指针法
	printf("*ppa = %c", *(*(*(ppa + 2) + 2) + 1));

}


//程序4
//分割字符串。用户输入一个英文句子，你的程序将这个字符串按空格进行分割，返回由单词组成的二维数组

void test4()
{
	char str[1024];
	char* p = str;//间接访问地址
	char* pos[1024] = { 0 };//初始化指针数组，用于记录每个单词的地址。

	int len = 0;
	printf("请输入一个英文句子:");
	while ((str[len++] = getchar()) != '\n' && len + 1 < 1024);
	str[len - 1] = '\0';//str[len]存放的是'\n'，将其替换为'\0';思考：为什么是str[len - 1]而不是str[len]呢



	int cWord = 0;//统计单词数
	int i = 0, j = 0;//初始化计数器
	if (*p != ' ')
	{
		pos[i++] = p;
		cWord++;
	}

	int cChar = 0;//统计字符数
	int max = 0;
	while (len--)
	{
		if (*p++ == ' ')
		{
			//判断最大字符数
			max = cChar > max ? cChar : max;
			cChar = 0;

			//到底了，退出循环
			if (*p == '\0')
			{
				break;
			}

			//单词数+1
			if (*p != ' ')
			{
				pos[i++] = p;
				cWord++;
			}
		}
		else //没有else会把空格计入进去
		{
			cChar++;
		}
	}
	max = --cChar > max ? cChar : max;//最后会多算一个'\0'，所以减去

	//申请可变长数组,max+1，否则'\0'放不下
	//char result[cWord][max + 1];源代码中这个地方是无法使用，是因为VS不支持直接使用可变长数组;也是得我们学习到内存分配，即malloc函数才能处理这个,我们能干的只有定义固定数组

	//使用固定大小的二维数组，假设每个单词最多100个字节
	char result[100][100];

	//将切割好的单词放进二维数组里面
	for (i = 0; i < cWord; i++)
	{
		for (j = 0; *(pos[i] + j) != ' ' && *(pos[i] + j) != '\0'; j++)
		{
			result[i][j] = *(pos[i] + j);
		}
		result[i][j] = '\0';
	}

	//打印结果
	printf("分割结果已存储到result[%d][%d]的二维数组中...\n", cWord, max+1);
	printf("现在依次打印每个单词:\n");
	for (i = 0; i < cWord; i++)
	{
		printf("%s\n", result[i]);
	}

}


//主函数
int main()
{
	/*
		索引						作用
		test1					二级指针的认识
		test2					作业解析，这个其实就是回顾指针数组和数组指针的应用
		test3					指针法访问三维数组的元素
		test4					指针数组和指向‘指针数组’的指针的应用
	*/
	test4();
	return 0;
}

